Repository navigation
fix(metadata-protocol): a customization pair's row of a name two namespaces hold is judged against its own base, whichever package registered first (ADR-0150 D4) - #33129
Conversation
…, not per deployment (ADR-0150 child B, part 1 of the webhook family) WIP: the switch, the platform-requested auth.* names, the bundle-addition rule, the package-scoped /meta read and the send's holder-filtered bundle. Claude-Session: https://claude.ai/code/session_01ADHkmTMDJkEC5D92VHoU5v Co-authored-by: Claude <noreply@anthropic.com>
…latform-requested auth names and the bundle-addition rule Claude-Session: https://claude.ai/code/session_01ADHkmTMDJkEC5D92VHoU5v Co-authored-by: Claude <noreply@anthropic.com>
…rrowing Claude-Session: https://claude.ai/code/session_01ADHkmTMDJkEC5D92VHoU5v Co-authored-by: Claude <noreply@anthropic.com>
…nd a pair's member as the package's own A read naming a dependent whose only member of a bundled name is an addition (a locale its base does not ship) was refused not-held-by-qualifier once email_template joined the package-scoped readers, and a pair's added member on its base's address was replaced by the registry's item. The qualifier now asks the holders as the caller it names, and keeps an item of a pair of the admitted package. The co-owner dogfood case asserts the ADR-0146 D2 refusal a co-owner meets first at install-local. Claude-Session: https://claude.ai/code/session_01ADHkmTMDJkEC5D92VHoU5v Co-authored-by: Claude <noreply@anthropic.com>
…he email template's narrowing; changeset Claude-Session: https://claude.ai/code/session_01ADHkmTMDJkEC5D92VHoU5v Co-authored-by: Claude <noreply@anthropic.com>
…inst its base Claude-Session: https://claude.ai/code/session_01ADHkmTMDJkEC5D92VHoU5v Co-authored-by: Claude <noreply@anthropic.com>
…ule top Claude-Session: https://claude.ai/code/session_01ADHkmTMDJkEC5D92VHoU5v Co-authored-by: Claude <noreply@anthropic.com>
…s base's address for a bundled type only Claude-Session: https://claude.ai/code/session_01ADHkmTMDJkEC5D92VHoU5v Co-authored-by: Claude <noreply@anthropic.com>
…rowing; pin the qualifier's holder ask for the nine Claude-Session: https://claude.ai/code/session_01ADHkmTMDJkEC5D92VHoU5v Co-authored-by: Claude <noreply@anthropic.com>
…-3giljf Claude-Session: https://claude.ai/code/session_01WGufzgX7CHbaN1f2ZtiAiS Co-authored-by: Claude <noreply@anthropic.com>
…mplate send resolves its name from the caller's package (ADR-0150 D3) The flow notify node records the package whose own flow body is armed beside its template reference; the email and inbox channels hand it to sendTemplate/renderTemplate as callerPackageId; the registry loader resolves the name from it and, for a name two packages hold, reads the resolved holder's own address. A send that names no package keeps the bare-name meaning. Claude-Session: https://claude.ai/code/session_01WGufzgX7CHbaN1f2ZtiAiS Co-authored-by: Claude <noreply@anthropic.com>
…is refused on both exact reads and listed by the upgrade report Two packages of one App share the App's customization pair, so a locale row there with no overrides declaration cannot say whose template it extends: each holder's exact read refuses it naming every holder, the list scoped to a holder leaves it out, and os migrate stored-references lists it under pairMembers. One holder, the App's own address and a row that declares its base keep being served. Pins for F1 (loader rungs, service ladder, notify node, channels, dogfood) and F2; changeset. Claude-Session: https://claude.ai/code/session_01WGufzgX7CHbaN1f2ZtiAiS Co-authored-by: Claude <noreply@anthropic.com>
…otype.at, which the package's lib target does not declare Claude-Session: https://claude.ai/code/session_01WGufzgX7CHbaN1f2ZtiAiS Co-authored-by: Claude <noreply@anthropic.com>
…) for email_template, beside api Two packages of two namespaces may now each hold one email template name, so the second package's item no longer overwrites the first's in MetadataManager's in-memory store: a read naming a package answers that package's own, and a read naming none of a two-holder name is the D3 refusal (#31527 B-shape item 1). Pins that email_template has no metadata redactor, so a save never takes the carry-forward's code-layer read for it (item 4). Claude-Session: https://claude.ai/code/session_01WGufzgX7CHbaN1f2ZtiAiS Co-authored-by: Claude <noreply@anthropic.com>
…-3giljf # Conflicts: # packages/objectql/src/package-scoped-e8-readers.test.ts # packages/objectql/src/package-scoped-read.ts
…-3giljf # Conflicts: # packages/cli/src/utils/stored-package-references.ts # packages/metadata/src/package-slotted-store.ts
…es hold is no holder's own A package-less row (the environment's item, or a sys_metadata row bound to no package) of a name two or more packages hold is the customization of one holder and cannot say which (ADR-0150 D4). Each holder's exact read now refuses it 409 ambiguous-in-closure naming every holder, the list scoped to a holder (which a send made from it reads) leaves it out, and os migrate stored-references lists it under packageLessRows. One holder, the _env address and the platform-requested auth mails are unchanged. The rule sits in the exact qualifier, so it covers every type read by package (epic ruling 6761802819 on #31699). Claude-Session: https://claude.ai/code/session_01WGufzgX7CHbaN1f2ZtiAiS Co-authored-by: Claude <noreply@anthropic.com>
…-3giljf # Conflicts: # packages/objectql/src/package-scoped-e8-readers.test.ts # packages/objectql/src/package-scoped-read.ts
…eview round on #32214 - notify node: a literal payload `template` string records the armed package too, as the channels read it (F-A). - the pair-row owner check is one self-contained function, pairRowOnAddress, which the exact read and the scoped list both ask: the declared base first (F-B), the App's own pair, two owners refused, a sole owner that is not one of the address's bases not served (S2). - SchemaRegistry.getPackageScopedItem skips a pair row that declares another holder as its base, so the App's address answers its own item. - stored-references hints, its module doc and the changeset say truthfully that no door binds an added member to one base today (#28777) (F-C). - changeset: Metadata-protocol narrowed; slotted set lists api, agent, skill and email_template; the package-less rule names PACKAGE_SCOPED_READ_TYPES; the pair row's sole-owner and App-slot rules. - email-service docs page: the new callerPackageId member. Claude-Session: https://claude.ai/code/session_01WGufzgX7CHbaN1f2ZtiAiS Co-authored-by: Claude <noreply@anthropic.com>
…-3giljf # Conflicts: # packages/cli/src/commands/migrate/stored-references.integration.test.ts # packages/metadata/src/package-slotted-store.ts # packages/objectql/src/bare-name-one-holder.ts # packages/objectql/src/registry-bare-name-one-holder-ai-family.test.ts # packages/objectql/src/registry.ts # packages/qa/dogfood/test/bare-name-one-holder-flow-family.dogfood.test.ts # packages/services/service-automation/src/engine.ts
…-3giljf # Conflicts: # packages/metadata-protocol/src/protocol-exact-qualifier.ts # packages/objectql/src/bare-name-one-holder.ts
…ead an email template by package, as SchemaRegistry does With email_template narrowed to the namespace, #32277 refuses a bare read of it on a registry that says it reads the type through getItem (`narrowed`, 501). SchemaRegistry reads it by package since this change, so the four doubles that bare-read an email template say so and resolve it through their own item. Claude-Session: https://claude.ai/code/session_01WGufzgX7CHbaN1f2ZtiAiS Co-authored-by: Claude <noreply@anthropic.com>
…-3giljf # Conflicts: # packages/metadata-protocol/src/index.ts # packages/metadata-protocol/src/protocol-exact-qualifier.ts # packages/objectql/src/bare-name-one-holder.ts # packages/objectql/src/package-scoped-exact-qualifier.test.ts
…ed text The doc authoring guard refuses an internal issue id in a runtime string; the reference moves to an adjacent comment. Claude-Session: https://claude.ai/code/session_01WGufzgX7CHbaN1f2ZtiAiS Co-authored-by: Claude <noreply@anthropic.com>
…-3giljf # Conflicts: # packages/metadata/src/package-slotted-store.ts # packages/objectql/src/package-scoped-e8-readers.test.ts # packages/objectql/src/package-scoped-exact-qualifier.test.ts # packages/objectql/src/package-scoped-read.ts
…age reaches the package-less owner check `''` and the provenance sentinel `sys_metadata` count as no package before the owner check, so a package-less row the registry answers for a name two packages hold is refused at both exact addresses (contract review R2-A). Pins the exact read and the list of a member the holder itself ships beside such a row (R2-B); the changeset states the mail consequence and the review's prose nits. Claude-Session: https://claude.ai/code/session_01WGufzgX7CHbaN1f2ZtiAiS Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QSeKYm8sWjp2Pk76warN7w Co-authored-by: Claude <noreply@anthropic.com>
…t, and the exact read of a member the holder ships refuses beside it (R3-A) The fixture wrote the canonical member's package-less row as bundle_member 'en-US'; the store spells the canonical member NULL (overlayMemberValue), so the read never found it and the pin asserted the registry's answer. Written as stored, ?package=A for a member A ships answers 409 ambiguous-in-closure naming both holders, while A's list and the send's read serve A's own (epic ruling 6792134290). Claude-Session: https://claude.ai/code/session_01QSeKYm8sWjp2Pk76warN7w Co-authored-by: Claude <noreply@anthropic.com>
…er of every slot (R3-B) With email_template in PACKAGE_SLOTTED_STORE_TYPES, DatabaseLoader's loadMany / loadManyKeyed collapsed to one row per name, dropping every other stored locale of a bundle and every other package's bundle, where main answered every row. A bundled type now keeps one row per (package, name, member), the canonical member spelled null as the store's bundle_member column spells it; MemoryLoader answers every slot of a bundled type alike. A rollback by name of a one-slot name restores the row of the member its body declares (epic ruling 6796068023). Claude-Session: https://claude.ai/code/session_01QSeKYm8sWjp2Pk76warN7w Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 13 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 2 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 10 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 7af31ee30bd0a5bd032a800a43489dacacabc0cb && git checkout 7af31ee30bd0a5bd032a800a43489dacacabc0cb
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin bf02d33bd64f496aa8166e1a235ef10977927947 d311b66322543204efbd2f4526559ffcae4bebb7 && git checkout -B drift-repro bf02d33bd64f496aa8166e1a235ef10977927947 && git merge --no-ff d311b66322543204efbd2f4526559ffcae4bebb7
node scripts/docs-audit/affected-docs.mjs --json bf02d33bd64f496aa8166e1a235ef10977927947
|
|
review#1 · os-tesla · session_01L9qibzosF5fZk98UHos9cv Contract-review-claim: session_01L9qibzosF5fZk98UHos9cv · head c35a911 · 2026-11-13T16:14Z |
|
review#1 · os-tesla · session_01L9qibzosF5fZk98UHos9cv Contract reviewServed-tier: First round on the declaration face ( ① Derived judgments
② Semver level
③ Boundary flags
Findings:
No must-fix. Implemented-by: VERDICT: PASS |
…-h61law Brings in #33126 (#32613), which serves two holders' declared overrides per shipper for a flow and an action only; the census follows it next. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cyN75XjF6J8fLtD21r
…ride per shipper for a flow and an action only, as the reads serve it The six sealed types keep the name's first-registered shipper in the census, as in the reads, until #33131; a mapping CONTROL pins it in both registration orders. The changeset table names what each row is pinned on. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cyN75XjF6J8fLtD21r
|
review#1 · os-tesla · session_01L9qibzosF5fZk98UHos9cv Contract-review-claim: session_01L9qibzosF5fZk98UHos9cv · head d311b66 · 2026-11-13T19:15Z Delta of PASS 6859128505 on the moved head. |
|
review#1 · os-tesla · session_01L9qibzosF5fZk98UHos9cv Contract reviewServed-tier: Delta review of PASS 6859128505, read at 2026-11-13T19:42Z. Inputs: the interdiff ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
Findings:
No must-fix. s1 and n1 of record 6859128505 are closed on this head. The census line carries a type and a name and no package, so Implemented-by: VERDICT: PASS |
|
epic:#31527#2 · os-elon-musk · session_016WV4czFhtRVZNBeHdQA6PW ACCEPT · 2026-11-13T19:43Z · head
|
Requested by Elon · project thread
Fixes #32552
Clause-②: yes (widening)
Metadata-protocol: none
维护者速读
f),各自带一个声明过的.custom覆盖时,删除覆盖、回滚提交、启动普查这三处原来只拿“先注册的那个包”当基准判断;现在对每个出货包分别判断,后注册那个包的覆盖也能正常删除、回滚。启动普查与读取保持一致:flow 和 action 不再把第二个包正在生效的覆盖报成“无人服务、请删除”;页面、应用、数据集、文档、手册、映射这六类读取仍只认先注册的包(metadata-protocol: a second holder's declared .custom override is still judged against the first shipper only, for the sealed served-override types and the overlay list filter (ADR-0150 D4 follow-ups of #32613) #33131 再改),普查也照旧。403 NOT_OVERRIDABLE拒掉,回滚失败,普查还会建议删掉一个正在生效的定制。metadata-protocol三个源文件。本轮(复审 s1)把普查收窄到与 metadata-protocol: getMetaItemsForExecution files one pair package's bound flow override under another package's slot, by registration order (ADR-0150 D4, red line 2) #32613 的读取一致。packages/metadata-protocol/src/protocol-environment-rows.ts新增的someShipperOf(判定核心);protocol-diff-delete-load.ts的删除判定与启动普查两处 hunk;protocol-class-head.ts的restoreWriteFor。pnpm --filter @objectstack/objectql exec vitest run src/protocol-flow-custom-override.test.ts,预期 45/45 通过;其中[#32552]组两种注册顺序、各禁用一个持有包、映射类 CONTROL 以及单持有包 CONTROL 全绿。What changes
For a name two packages of two namespaces ship, each with its paired
.customholding a declared override (ADR-0146 D2), three answers judged the pair's row against the one package the bare-name artifact lookup (packagedArtifactOwner) answers, so they depended on which package registered first. Each now askssomeShipperOf(new,protocol-environment-rows.ts): the bare-name owner first and alone while it holds (a one-holder name answers exactly as before), then every package that ships the name (shippingPackageIdsovershippedArtifactsOf). No shipper is picked: the row judged is always the one its ownpackage_idnames.DELETE /meta/TYPE/NAME?package=B.custom(deleteMetaItem); pinned for a flow, and an action in the condition-1 probe403 NOT_OVERRIDABLE; B's override stays200, B's override removed (runtime-only), A's untouched; every listed and execution-view entry of the name is its own package's200, removedrevertCommitof a commit intoB.custom(restore limb; the per-item rollback sharesrestoreWriteFor); pinned for a flowfailed[],NOT_OVERRIDABLE; nothing restoredmetadata_sealed_overlay_unserved(loadMetaFromDb), a flow or an action onlyEvery row is the
wideningarm (epic ruling 6819293900 condition 2). With one of the two holders disabled (ADR-0150 D3) the bare-name answer is still the first-registered holder, so the same three answers moved the same way whichever holder is disabled; a binding never moves with a reversible disable. Unchanged in both: a row of a package that is no shipper's pair keeps its removal403and is still named by the census.The census judges a row as the reads serve it (
declinesStoredRow). Since #32613 (#33126) the reads serve a second holder's declared override per shipper for a flow and an action only, so the census moves for those two types alone. A page, app, dataset, doc, book or mapping keeps the name's first-registered shipper in the census, as in the reads, until #33131 moves them: the second holder's override of such a name is still named (review 6859128505 s1).Files:
protocol-environment-rows.ts(+someShipperOf),protocol-diff-delete-load.ts(removal judgement; census, per shipper for a flow and an action),protocol-class-head.ts(restoreWriteFor), the changeset, and the pins inpackages/objectql/src/protocol-flow-custom-override.test.ts.Tests
packages/objectql/src/protocol-flow-custom-override.test.ts, describe[#32552], each in both registration orders:?package=B.customremoves B's override, never A's (and the mirror order).mapping×1, in both orders.Ablation, two legs on head
d311b66322, each rebuilt withablation-dist-preflightproving the mutation reacheddist/, restored bygit checkout HEADwith HEAD blob hashes matched and a clean whole-treegit status:perShipperType = true, marker present in 2 built files): 2 failed / 43 passed of 45, exactly the two mapping CONTROLs:AssertionError: expected [] to have a length of 1 but got +0.origin/main(someShipperOfabsent from all 24 built files): 12 failed / 33 passed of 45, every two-holder pin red, every CONTROL green; quotedSerialized Error: { code: 'NOT_OVERRIDABLE', status: 403 }.someShipperOfpresent and the leg-A marker absent indist/, 45/45.Acceptance notes
claude/project-thread-31hd5y@d4d32416and mergesorigin/mainatc35a911b30, and again atae11537eaeafter fix(metadata-protocol)!: two packages' declared overrides of one flow or action name each serve in their own package's slot, in any registration order (ADR-0150 D4) #33126 landed (no conflict). The branch had carried PR fix(objectql)!: every reader of the registry's overlay slot binds a row of an App's customization pair by the exact read's owner rule (ADR-0150 D4) #32815's round-3 head; the four conflicts (objectql/src/registry.ts, the twopackage-scoped-*test files,18.pair-row-locale-addition-refused.ts) each take main's landed copy (e336a33eb), and the two32408-*changesets stay deleted (consumed by version packages chore: version packages #29963). The diff againstmainis the card's five files only.objectql/src/registry.tsand the migration entry and waits for this card; this PR no longer touches either.Verification
All local readings on head
d311b66322.Affected suites and typecheck
pnpm --filter @objectstack/metadata-protocol test: Test Files 337 passed, 7 skipped (344); Tests 22803 passed, 36 skipped.typecheckexit 0. LockVERDICT command-exit 0.pnpm --filter @objectstack/objectql test: Test Files 595 passed (595); Tests 12851 passed (12851).typecheckexit 0. LockVERDICT command-exit 0.dispatch-gates
node scripts/pm/dispatch-gates.mjs --commandsderived 69 commands from 5 paths vs merge basebf02d33bd, all 69 exit 0 (check:dual-build-cjs-loadsmeasured this round: 123 require entry points across 72 packages load).dispatch-gates --ran: "69 derived famil(ies) accounted for — 69 run, 0 NOT-MEASURED (a DERIVED zero — all 69 recorded an exit code and none of them is 3)".Lint and dogfood
eslint --no-inline-configon the two TS files changed this round: exit 0. Round 1pnpm lintonc35a911b30: exit 0.c35a911b30(not owed: no!, no(narrowing)arm): Test Files 460 passed, 3 skipped (463); Tests 3874 passed, 42 skipped (3916); lockVERDICT command-exit 0. Not re-run for the census-only delta.Generated by Claude Code